﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.StorageClient;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.WindowsAzure;
using System.IO;
using System.Threading;

namespace Melos
{
    /**
     * Generic ms-azure queue wrapper class
     * usage: putItem() - getItem() - itemDone()
     */
    public abstract class GenericQueue
    {
        // buffer for serialization
        const int BUFFER_SIZE = 1000;
        CloudQueue cq;
        BinaryFormatter formatter = new BinaryFormatter();
        public string queueName;
        /**
         * contructor
         */
        public GenericQueue(CloudStorageAccount sa, String queueName)
        {
            this.queueName = queueName;
            getQueue(sa);
        }
        public CloudQueue getQueue(CloudStorageAccount sa) {
            cq = sa.CreateCloudQueueClient().GetQueueReference(queueName);
            cq.CreateIfNotExist();
            return cq;
        }
        /**
         * puts an item into the queue after heving serialized it
         */
        public void putItem(Object wqi){
            Stream str = new MemoryStream();
            formatter.Serialize(str,wqi);
            str.Seek(0,SeekOrigin.Begin);

            Byte[] buffer = new Byte[(int)str.Length];
            str.Read(buffer, 0, (int)str.Length);
            cq.AddMessage(new CloudQueueMessage(buffer));
        }
        private CloudQueueMessage currentMessage;
        /**
         * Gets an item from queue, and deserializes it
         * the operation is blocking, i.e. it will never return if the queue is always empty
         */
        public Object getObject() {
            Stream str = new MemoryStream();
            currentMessage = getQueueMessage();
            str.Write(currentMessage.AsBytes, 0, currentMessage.AsBytes.Length);
            str.Seek(0,SeekOrigin.Begin);
            return formatter.Deserialize(str);
        }
        // the below method should use generics, and then there would be no need to extend this class 
        // public abstract Object getItem();
       
        /**
         * deletes current work item from queue
         */
        public void itemDone() {
            cq.DeleteMessage(currentMessage);
        }
        private int sleepInterval = 1000;
        public int maxSleepInterval = 10000;
        private void sleep() {
            Thread.Sleep(sleepInterval); // a getMessage pénzbe kerül
        }
        // this method handles adaptive queue polling
        private CloudQueueMessage getQueueMessage()
        {
            CloudQueueMessage tmp = null;
            while (tmp == null){
                tmp = cq.GetMessage();
                sleep();
                if (sleepInterval > maxSleepInterval)
                    sleepInterval *= 2;
                else sleepInterval = 1;
            }

            return tmp;
        }
    }
}
